/*
 * Hosted Game: Deathmatch
 * D1st0rt, SSCE Hyperspace
 * License: MIT/X11
 * Created: 2009-01-15
 *
 * Simple deathmatch module that functions as a very basic demo of how
 * to make a game run on top of the Hosted Game core
 */

///////////////////////////////////////////////////////////////////////
// Includes
///////////////////////////////////////////////////////////////////////

#include "stdio.h"
#include "string.h"
#include "asss.h"
#include "persist.h"
#include "statcodes.h"
#include "hgcore.h"

///////////////////////////////////////////////////////////////////////
// Interfaces
///////////////////////////////////////////////////////////////////////

local Imodman *mm;
local Ilogman *lm;
local Ichat *chat;
local Igame *game;
local Icmdman *cmd;
local Iplayerdata *pd;
local Ipersist *persist;
local Istats *stats;
local Ihgcore *hgcore;

///////////////////////////////////////////////////////////////////////
// Defines/Types
///////////////////////////////////////////////////////////////////////
typedef struct dm_teamdata
{
	int Kills;
}dm_teamdata;

#define HGR_KILLS_REACHED 1

///////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////

local pthread_mutex_t globalmutex;

EXPORT const char info_hg_dm[] = "09.05.12 by D1st0rt <d1st0rter@gmail.com>";

///////////////////////////////////////////////////////////////////////
// Interface Prototypes
///////////////////////////////////////////////////////////////////////
local int OnPrepare(Arena *a, Player *host, const char *params);
local int OnStart(Arena *a, Player *host);
local void OnGameover(Arena *a, int how);
local void OnCleanup(Arena *a);
local void OnTeamCreate(Arena *a, HGTeam *team);
local void OnTeamDestroy(Arena *a, HGTeam *team);
local int SizeOfTeamData();
local void TeamInfoString(HGTeam *team, char *str, int buflen);
///////////////////////////////////////////////////////////////////////
// Prototypes
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////
local void PlayerKill(Arena *a, Player *k, Player *d, int bty, int flags, int greens);

///////////////////////////////////////////////////////////////////////
// Timers
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Commands
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Entry Point
///////////////////////////////////////////////////////////////////////
local Ihostedgame interface =
{
	INTERFACE_HEAD_INIT(I_HOSTEDGAME, "hg_dm")

	OnPrepare,
	OnStart,
	OnGameover,
	OnCleanup,
	OnTeamCreate,
	OnTeamDestroy,
	SizeOfTeamData,
	TeamInfoString
};

EXPORT int MM_hg_dm(int action, Imodman *mm_, Arena *arena)
{
	if (action == MM_LOAD)
	{
	    // Global interfaces
		mm = mm_;
		chat    = mm->GetInterface(I_CHAT,		 ALLARENAS);
		cmd	    = mm->GetInterface(I_CMDMAN,	 ALLARENAS);
		pd      = mm->GetInterface(I_PLAYERDATA, ALLARENAS);
		game    = mm->GetInterface(I_GAME,		 ALLARENAS);
		lm 		= mm->GetInterface(I_LOGMAN, 	 ALLARENAS);
		persist = mm->GetInterface(I_PERSIST,    ALLARENAS);
		stats   = mm->GetInterface(I_STATS,      ALLARENAS);
		hgcore  = mm->GetInterface(I_HGCORE,     ALLARENAS);

		if (!chat || !cmd || !pd || !game || !lm || !persist || !hgcore || !stats)
			return MM_FAIL;

		// Data

        // Locking
		pthread_mutexattr_t attr;
		pthread_mutexattr_init(&attr);
		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
		pthread_mutex_init(&globalmutex, &attr);
		pthread_mutexattr_destroy(&attr);

		return MM_OK;
	}
	else if (action == MM_UNLOAD)
	{
        // Locking
		pthread_mutex_destroy(&globalmutex);

		// Data

        // Global interfaces
		mm->ReleaseInterface(hgcore);
		mm->ReleaseInterface(stats);
		mm->ReleaseInterface(persist);
		mm->ReleaseInterface(lm);
		mm->ReleaseInterface(game);
		mm->ReleaseInterface(pd);
		mm->ReleaseInterface(cmd);
		mm->ReleaseInterface(chat);

        return MM_OK;
	}

	else if (action == MM_ATTACH)
	{
		// Interface registration
		mm->RegInterface(&interface, arena);
		hgcore->AttachGame(arena, I_HOSTEDGAME, "hg_dm");

		//Data

		//Attached interfaces

		//Callbacks
		mm->RegCallback(CB_KILL, PlayerKill, arena);

		//Timers

		//Commands


		return MM_OK;
	}
	else if (action == MM_DETACH)
	{
		//Data

		//Timers

		//Callbacks
		mm->UnregCallback(CB_KILL, PlayerKill, arena);

		//Commands

		// Interface registration
		if(!hgcore->DetachGame(arena))
		{
			return MM_FAIL;
		}

	    if (mm->UnregInterface(&interface, arena))
		{
			return MM_FAIL;
		}

		return MM_OK;
	}

	return MM_FAIL;
}

///////////////////////////////////////////////////////////////////////
// Interface Functions
///////////////////////////////////////////////////////////////////////
local int OnPrepare(Arena *a, Player *host, const char *params)
{
	chat->SendArenaMessage(a, "Deathmatch! First team to 5 kills wins!");
	return 1;
}

local int OnStart(Arena *a, Player *host)
{
	Target t;
	t.type = T_ARENA;
	t.u.arena = a;
	persist->EndInterval(NULL, a, INTERVAL_RESET);
	game->GivePrize(&t, PRIZE_WARP, 1);
	game->ShipReset(&t);
	return 1;
}

local void OnGameover(Arena *a, int how)
{
	if(how == HGR_STOPPED)
	{
		chat->SendArenaMessage(a, "Deathmatch game stopped by host.");
	}
	else if(how == HGR_NONE_REMAINING)
	{
		chat->SendArenaMessage(a, "Deathmatch game cancelled because there is nobody left.");
	}
	else if(how == HGR_CANCELLED)
	{
		chat->SendArenaMessage(a, "Deathmatch game cancelled by host.");
	}
	else if(how == HGR_KILLS_REACHED)
	{
		int mvpkills = 0;
		int kills = 0;
		Player *mvp;

		Player *p;
		Link *link;
		pd->Lock();
		FOR_EACH_PLAYER(p)
		{
			if(p->arena == a)
			{
				kills = stats->GetStat(p, STAT_KILLS, INTERVAL_RESET);
				if(kills > mvpkills)
				{
					mvpkills = kills;
					mvp = p;
				}
			}
		}
		pd->Unlock();

		chat->SendArenaMessage(a, "%s is the MVP with %d kills!", mvp->name, mvpkills);
	}
}

local void OnCleanup(Arena *a)
{
	//nothing required
}

local void OnTeamCreate(Arena *a, HGTeam *team)
{
	chat->SendArenaMessage(a, "Team %d added!", team->Freq);
}

local void OnTeamDestroy(Arena *a, HGTeam *team)
{
	//nothing required
}

local int SizeOfTeamData()
{
	return sizeof(dm_teamdata);
}

local void TeamInfoString(HGTeam *team, char *str, int buflen)
{
	int offset = strlen(str);
	dm_teamdata *data = hgcore->GetTeamData(team->Arena, team->Freq);
	char *buf = (char *)(((char*)str)+offset);
	sprintf(buf, "\nKills: %d", data->Kills);
}
///////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////
local void PlayerKill(Arena *a, Player *k, Player *d, int bty, int flags, int greens)
{
	if(hgcore->GameStatus(a) == HGS_ACTIVE)
	{
		dm_teamdata *data = hgcore->GetTeamData(a, k->p_freq);
		data->Kills += 1;
		if(data->Kills >= 5)
		{
			chat->SendArenaMessage(a, "Team %d wins!", k->p_freq);
			hgcore->EndGame(a, HGR_KILLS_REACHED);
		}
	}
}

///////////////////////////////////////////////////////////////////////
// Timers
///////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////
// Commands
///////////////////////////////////////////////////////////////////////

